/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_SELF_CCD_MSM_COLLISION_DETECTION_HANDLER_H
#define SX_SELF_CCD_MSM_COLLISION_DETECTION_HANDLER_H

#include <sxCollisionDetectionHandler.h>
#include <sxTriangleSoupCollisionEventAggregate.h>
#include <sxMassSpringMesh.h>

/* SelfCCD Includes */
#include <DeformModel.h>

using Sx::Simulation::Objects::MassSpringMesh;
using Sx::Physics::Collision::Aggregates::TriangleSoupCollisionEventAggregate;
using Sx::Physics::Collision::Handlers::CollisionDetectionHandler;

namespace Sx {
namespace SelfCCD {
namespace Handlers {
namespace Detection {

/* This structure is used to register a pointer to an object that has been
* included in the Self-CCD collision model. Since the indices reported by
* the Self-CCD listener interface are global (reference the collection of
* all vertices in all objects in the model), a lookup table is required
* to determine the vertices original object and its local position in the
* objects vertex array. This collision index lookup table must be
* initialized every time the Self-CCD model is constructed.
*/
struct CCD_CollisionLookupPair {
	CCD_CollisionLookupPair() {
		this->localIndex = 0;
		this->mesh = nullptr;
	}

	CCD_CollisionLookupPair(unsigned int localIndex, const std::shared_ptr<MassSpringMesh>& mesh) {
		this->localIndex = localIndex;
		this->mesh = mesh;
	}
		
	unsigned int localIndex;
	std::shared_ptr<MassSpringMesh> mesh;
};

class SelfCCD_MSM_CollisionDetectionHandler : public CollisionDetectionHandler<MassSpringMesh, TriangleSoupCollisionEventAggregate<MassSpringMesh> >, public CCD_EventListener {
public:
	SelfCCD_MSM_CollisionDetectionHandler();
	virtual ~SelfCCD_MSM_CollisionDetectionHandler();

	/* Collision Detection Handler Interface */
	bool construct(Util::ArrayList<std::shared_ptr<MassSpringMesh> >& objects);
	bool update(Util::ArrayList<std::shared_ptr<MassSpringMesh> >& objects, TriangleSoupCollisionEventAggregate<MassSpringMesh>* const collisionData);
	bool performDetection(Util::ArrayList<std::shared_ptr<MassSpringMesh> >& objects, TriangleSoupCollisionEventAggregate<MassSpringMesh>* const collisionData);

	void reset(Util::ArrayList<std::shared_ptr<MassSpringMesh> >& objects);

	/* Self-CCD Event Listener Interface */
	bool onVertexFaceCollision(unsigned int vertex_index, unsigned int triangle_vertex0_index, unsigned int triangle_vertex1_index, unsigned int triangle_vertex2_index, float t);
	bool onEdgeEdgeCollision(unsigned int edge0_vertex0_index, unsigned int edge0_vertex1_index, unsigned int edge1_vertex0_index, unsigned int edge1_vertex1_index, float t);

protected:
	/* POINTER_OWNERSHIP: YES */
	DeformModel* model;

	/* Cached vertex list */
	vec3f_list modelVertices;

	/* 
	 * Internal pointer to the collision data so that the Self-CCD interface
	 * functions can create new collision events.
	 * POINTER_OWNERSHIP: NO
	 */
	Physics::Collision::Aggregates::TriangleSoupCollisionEventAggregate<MassSpringMesh>* collisionData;

	/* Collision lookup table and functions. */
	Util::ArrayList<CCD_CollisionLookupPair> collisionLookupTable;
	bool getMesh(unsigned int globalIndex, std::shared_ptr<MassSpringMesh>& outMesh);
	bool getLocalIndex(unsigned int globalIndex, unsigned int& outLocalIndex);
};

}

}

}

}

#endif
